/**
 * @overview 基于项目中的 WebGis 及 Cesium 再次封装的三维地图工具类
 * @author chenli
 * @update  2020.11.26
 */
import CesiumMap3DControl from './CesiumMap3DControl'

class Map3DControl extends CesiumMap3DControl {
  constructor(map) {
    super(map.map3D)
    this.map = map
    this.featureList = []
    this.heatMap = null // 热力图
    this.mapOverlay = new Map() // 覆盖层
    this.eventList = [] // 地图事件列表
    this.satelineManager = null // 卫星数据列表
    this.weather = null // 天气数据
    this.flyLineFeatures = [] // 飞线动画数据表
    this.pointRipper = null
    this.pointRipperList = [] // 点扩散集合， 用于一组点扩散效果
    this.infoWindowObj = [] // 地图弹窗
    this.rain = null // 雨 天气效果
    this.njGridGeojson = null // 网格叠加分析数据 (线条数据)
    this.microStationPolygon = null // 网格叠加分析
    // 漫游全局参数
    this.stopPoint = null
    this.roamStop = false
    this.manipulatePoints = []
    this.v = 0
  }

  /**
   * 获取feature
   * @param featureName {String} feature名称
   * @returns {null|*}
   */
  getFeature(featureName) {
    const existFeature = this.featureList.filter((item) => item.featureName === featureName)
    if (existFeature.length) {
      return existFeature[0]
    }
    return null
  }

  /**
   * 从工具类处添加feature到地图上，用于维护featureList
   * @param {String} featureName 添加的feature表示 唯一
   * @param {CgsFeature} feature feature数据
   */
  addFeature(featureName, feature) {
    const existFeature = this.featureList.filter((item) => item.featureName === featureName)
    if (existFeature.length) {
      existFeature[0].feature.setVisible(true)
      return
    }
    this.featureList.push({
      featureName: featureName,
      feature: feature,
    })
    this.map.addFeature(feature)
  }

  /**
   * 根据featureName移除工具类所维护的地图feature
   * @param {String} featureName
   */
  removeFeature(featureName) {
    for (const [index, item] of this.featureList.entries()) {
      if (item.featureName === featureName) {
        this.map.removeFeature(item.feature)
        this.featureList.splice(index, 1)
        break
      }
    }
  }

  /**
   * 移除地图工具类所维护的所有feature数据
   */
  removeAllFeature() {
    for (const item of this.featureList.values()) {
      if (item.feature) {
        this.map.removeFeature(item.feature)
      }
    }
    this.featureList = []
  }

  /**
   * 根据featureName隐藏工具类所维护的地图feature
   * @param {String} featureName 要素名称
   */
  hiddenFeature(featureName) {
    for (const item of this.featureList.values()) {
      if (item.featureName === featureName) {
        item.feature.setVisible(false)
        break
      }
    }
  }

  /**
   * 根据要素名称包含关系隐藏feature
   * @param {String} containContext 包含的文本
   */
  hiddenFeatureByContainName(containContext) {
    for (const item of this.featureList.values()) {
      if (item.featureName.includes(containContext)) {
        item.feature.setVisible(false)
      }
    }
  }

  /**
   * 根据要素名称包含关系隐藏feature
   * @param {String} containContext 包含的文本
   */
  removeFeatureByContainName(containContext) {
    for (let i = 0; i < this.featureList.length; i++) {
      if (this.featureList[i].featureName.includes(containContext)) {
        this.map.removeFeature(this.featureList[i].feature)
        this.featureList.splice(i, 1)
        i--
      }
    }
  }

  /**
   * 根据要素名称包含关系显示feature
   * @param {String} containContext 包含的文本
   */
  showFeatureByContainName(containContext) {
    for (const item of this.featureList.values()) {
      if (item.featureName.includes(containContext)) {
        item.feature.setVisible(true)
      }
    }
  }

  /**
   * 隐藏地图工具类所维护的所有feature数据
   */
  hiddenAllFeature() {
    for (const item of this.featureList.values()) {
      item.feature.setVisible(false)
    }
  }

  /**
   * @description 向地图添加图片feature数据
   * @param {Object} config 配置项
   *                  {
   *                      position: {Array} 位置
   *                      name: {String} 名称
   *                      type: {String} 添加的图片类型， 根据type去加载所需的地图
   *                      url: {String}, // 如果 type不符合条件，必须添加图片url
   *                      info: {Object} 图标携带数据
   *                      click: {Function} 点击事件回调函数
   *                      visibleHeight: {Array} 图标可视高度, 如[0, 1000], 默认[0, 300000]
   *                      labelVisibleHeight: {Array} 图标名称可视高度, 默认 [0, 5000]
   *                      labelShow: {Boolean} 图标名称可见, 默认true
   *                  }
   * @return CgsMark
   */
  createImagePoint(config) {
    const opt = {
      position: config.position,
      name: config.name,
      info: config.info,
      url: config.url,
      positioning: 'center-bottom',
      scale: config.scale || 0.6,
      click: config.click,
      custom: config.params,
      pixelOffset: [0, -20],
    }
    const markFeature = new CgsMark(opt)
    markFeature.secondName = config.id
    // 不显示label
    if (config.labelShow === false) {
      markFeature.setLabelVisible(false)
    }
    // 不显示feature
    if (config.show === false) {
      markFeature.setVisible(false)
    }
    markFeature.id = config.id
    markFeature.setVisibleHeight(config.visibleHeight || [0, 300000])
    markFeature.setLabelOffset([3, 0])
    markFeature.setFont('100 1px 微软雅黑')
    markFeature.setLabelFillColor('rgba(0,0,0,0)')
    markFeature.setLabelOutlineColor('rgba(0,0,0,0)')
    markFeature.setLabelOutlineWidth(0)
    // markFeature.setFont('600 14px 微软雅黑');
    // markFeature.setLabelFillColor('#000');
    // markFeature.setLabelOutlineColor('#fff');
    // markFeature.setLabelOutlineWidth(1);
    markFeature.feature3D.label.setVisibleHeight(config.labelVisibleHeight || [0, 5000])

    // 更改Cesium属性设置点位数据贴地形
    // markFeature.feature3D.entity.billboard.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND;
    // markFeature.feature3D.label.entity.label.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND;
    markFeature.feature3D.entity.billboard.disableDepthTestDistance = Number.MAX_SAFE_INTEGER
    markFeature.feature3D.label.entity.label.disableDepthTestDistance = Number.POSITIVE_INFINITY // label不被地形遮挡

    return markFeature
  }

  createArrowLine(config) {
    if (!config.id) {
      return
    }
    //箭头线
    const optArrowline = {
      positions: config.positions,
      name: config.text || '',
      followSurface: config.followSurface,
      fillColor: config.fillColor,
      width: config.width || 3,
      lineType: 3,
      labelfont: '12px 宋体',
      labeloffset: config.labeloffset,
    }
    const arrowline = new CgsLine(optArrowline)
    this.addFeature(config.id, arrowline)

    if (config.show !== undefined) {
      arrowline.setVisible(config.show)
    }
  }

  /**
   * @description 绘制圆形
   * @param {Object} config 配置数据
   */
  createCircle(config) {
    if (!config.center) {
      return
    }

    const opt = {
      position: config.center,
      radius: config.radius || 300,
      fillCollor: config.fillColor || 'rgba(255, 0, 0, 0.1)',
      outlineColor: config.outlineColor || 'rgba(255,0,0,1)',
    }
    const circleFeature = new CgsCircle(opt)
    circleFeature.feature3D.entity.ellipse.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND
    return circleFeature
  }

  /**
   * @description 绘制多边形
   * @param {Object} config 配置项
   *                  {
   *                      coordinates: Array[][][], 数据集
   *                      name: String, 名称标签
   *                      type: String, 类别
   *                      info: Object, 携带数据,
   *                      fillColor: String 填充颜色
   *                  }
   */
  createPolygon(config) {
    const opt = {
      positions: config.positions,
      name: config.name || '',
      info: config.info,
      fillColor: config.fillColor || 'rgba(0, 255, 255, 0.1)',
      outlineWidth: 2,
      outlineColor: config.outlineColor || 'rgba(0, 153, 255, 1.0)',
      click: config.click || null,
    }
    const polygonFeature = new CgsPolygon(opt)
    polygonFeature.setFont('14px 微软雅黑')
    if (config.info && config.info.centerLat && config.info.centerLon) {
      polygonFeature.feature3D.label.setPosition([config.info.centerLon, config.info.centerLat])
    }

    // 设置贴地
    if (config.isFollowSurface) {
      polygonFeature.feature3D.entity.polygon.heightReference =
        Cesium.HeightReference.CLAMP_TO_GROUND
    }

    switch (config.type) {
      case 'district':
        polygonFeature.setVisibleHeight([10000, 500000])
        break
      case 'city':
        polygonFeature.setVisibleHeight([500001, 2000000])
        break
      case 'province':
        polygonFeature.setVisibleHeight([2000001, 12000000])
        break
      case 'country':
        polygonFeature.setVisibleHeight([12000001, 30000000])
        break
      default:
        break
    }
    return polygonFeature
  }

  /**
   * @description 基于webgis的绘制简单线条
   * * @param {Object} config 配置项
   *                  {
   *                      coordinates: Array[][][], 数据集
   *                      name: String, 名称标签
   *                      lineType: String, 线的类型, 0 普通线, 1 发光线, 2 轮廓线, 3 箭头线
   *                      info: Object, 携带数据,
   *                      fillColor: String 填充颜色
   *                  }
   */
  createLine(config) {
    if (!config.coordinates && !Array.isArray(config.coordinates)) {
      return
    }

    const lineFeature = new CgsLine({
      positions: config.coordinates,
      name: config.name || '',
      lineType: config.lineType || 0,
      followSurface: true,
      fillColor: config.fillColor || 'rgba(255,0,0,1)',
    })

    return lineFeature
  }

  /**
   * @description 基于webgis的绘制动态宽线
   * * @param {Object} config 配置项
   *                  {
   *                      positions: Array[][][], 数据集
   *                      name: String, 名称标签
   *                      lineType: String,
   *                      fillColor: String 填充颜色
   *                      show: 显隐
   *                  }
   */
  createWineLine(config) {
    if (!config.positions && !Array.isArray(config.positions)) {
      return
    }

    const lineFeature = new CgsWideLine(config)

    return lineFeature
  }

  /**
   * @description 加载模型数据
   * @param {Object} config 配置项
   *                  {
   *                      position: {Array} 位置
   *                      name: {String} 名称
   *                      url: {String} 模型地址
   *                  }
   * @returns {CgsModel}
   */
  createModel(config) {
    const opt = {
      name: config.name,
      position: config.position,
      uri: config.uri,
      scale: config.scale || 1.0,
      rotation: config.rotation || [0, 0, 0],
    }
    const modelFeature = new CgsModel(opt)
    // modelFeature.setVisibleHeight([0, 2000000]);
    // modelFeature.setLabelOffset([0, -12]);
    modelFeature.setFont('12px 微软雅黑')

    return modelFeature
  }

  /**
   * @description 绘制热力图
   * @param {Object} options 热力图参数数据
   *                 {
   *                     dataList: {Array} [] 数据源 形如: {x:1,y:1,value:1}
   *                     radius: {Number} 数据点影响半径, px, 默认 8
   *                     blur: {Number} 模糊处理程度， [0,1], 默认 0.85
   *                 }
   */
  drawHeatMap(options) {
    if (!options.dataList) {
      return
    }

    if (!options.radius) {
      options.radius = 8 // 默认权重 8
    }

    if (!options.blur) {
      options.blur = 0.85 // 默认值 0.85
    }
    this.heatMap = new CgsHeatMap({
      map: this.map,
      radius: options.radius,
      blur: options.blur,
    })
    this.heatMap.setData({
      data: options.dataList,
    })
    this.heatMap.reDraw()
  }

  /**
   * @description 移除热力图
   */
  clearHeatMap() {
    if (this.heatMap) {
      this.heatMap.remove()
      this.heatMap = null
    }
  }

  /**
   * @description 卫星过境数据展示
   * @param {Object} options 配置项
   *                  {
   *                      speed: {Number} 卫星移动速度 默认1.0
   *                      beginTime: {String} 开始时间字符 格式 "2020-12-02 14:20:00"
   *                      endTime: {String} 结束时间字符 格式 "2020-12-02 14:20:00"
   *                  }
   * @return {CgsSatelineManager} satelineManager
   */
  createSateline(options) {
    const opt = {
      mapObject: window.map,
      url: 'CGS-2.3.0.21/SDK/assets/sateline/satelliteDateExp.xml',
      speed: options.speed || 1.0,
      pastColor: 'rgba(0,255,0,1.0)',
      predictColor: 'rgba(255,0,0,1.0)',
      beginTime: options.beginTime || '2020-12-02 14:20:00',
      endTime: options.endTime || '2020-12-02 14:50:00',
      labelFont: '18px 微软雅黑',
      labelFillColor: 'rgba(255,217,39,1.0)',
      labelStrokeColor: 'rgba(255,255,255,1.0)',
      labelOutlineWidth: 1,
      labelPixelOffset: [30, 30],
      labelStyle: 2,
    }

    this.satelineManager = new CgsSatelineManager(opt)
    return this.satelineManager
  }

  /**
   * 清除卫星数据
   */
  clearSateline() {
    if (this.satelineManager) {
      this.satelineManager.clear()
    }
  }

  /**
   * @description 添加地图上天气效果
   * @param {Object} config {
   *                 type: {String} "rain" || "snow"
   *                 density: {Number} [0,1] 密度, 默认 0.6
   *                 visibleHeight: {Number} 可视高度, 默认 40000
   * }
   */
  createWeather(config) {
    const opt = {
      type: config.type,
      show: true,
      density: config.density || 0.6,
      visibleHeight: config.visibleHeight || 30000,
    }
    this.weather = new CgsPrecipitation(opt)
    window.map.addFeature(this.weather)
  }

  /**
   * 移除天气效果
   */
  clearWeather() {
    if (this.weather) {
      this.weather.setVisible(false)
    }
  }

  /**
   * 地图上某个点的扩散效果
   * @param {Object} config
   *                      {
   *                          position: [][], 数据点
   *                          radius: Number, 半径，默认 20
   *                          duration: Number, 时间间隔（ms），默认 2000
   *                          color: String, 波纹颜色 rgba, 默认 rgba(0, 255, 32, 0.4)
   *                      }
   */
  createOnePointRipper(config) {
    this.removeOnePointerRipper()

    if (!config.position) {
      return
    }

    try {
      const pointRipper = new CgsCircleAnimation({
        position: config.position,
        radius: config.radius || 20,
        fillColor: config.color || 'rgba(0, 255, 32, 0.4)',
        duration: 2000,
      })
      this.map.addFeature(pointRipper)
      this.pointRipper = pointRipper
    } catch (e) {
      console.log('点波纹效果错误, ', e)
    }
  }

  /**
   * 地图上一系列点的扩散效果
   * @param {Object} config
   *                      {
   *                          positionList: [][], 数据点集
   *                          radius: Number, 半径，默认 20
   *                          duration: Number, 时间间隔（ms），默认 2000
   *                          color: String, 波纹颜色 rgba, 默认 rgba(0, 255, 32, 0.4)
   *                      }
   */
  createPointRipperList(config) {
    this.removeAllPointRipperList()

    if (!config.positionList) {
      return
    }

    for (const point of config.positionList.values()) {
      try {
        const pointRipper = new CgsCircleAnimation({
          position: point,
          radius: config.radius || 20,
          fillColor: config.color || 'rgba(0, 255, 32, 0.4)',
          duration: 2000,
        })
        this.map.addFeature(pointRipper)
        this.pointRipperList.push(pointRipper)
      } catch (e) {
        console.log('点波纹效果错误, ', e)
      }
    }
  }

  /**
   *
   */
  removeAllPointRipperList() {
    for (const point of this.pointRipperList.values()) {
      window.map.removeFeature(point)
    }
    this.pointRipperList = []
  }

  /**
   *
   * @param {Object} config
   */
  removeOnePointerRipper() {
    if (this.pointRipper) {
      window.map.removeFeature(this.pointRipper)
      this.pointRipper = null
    }
  }

  /**
   * @description 地图飞线动画效果, 两两成对组成一个飞线结构，起点为自左向右
   * @param {Array} 数据列表 dataList
   *                          [
   *                              {
   *                                  name: {String} // 路径名称
   *                                  startPtn: {Array} // 起始点坐标
   *                                  endPtn: {Array} // 结束点坐标
   *                                  startPtnFillColor: {String} 'rgba()' // 起始点波纹颜色设置, 默认 rgba(0, 255, 32, 1)
   *                                  startPtnRadius: {Number} // 起始点波纹大小, 默认15
   *                                  endPtnFillColor: {String} 'rgba()' // 起始点波纹颜色设置, 默认 rgba(255, 64, 0, 1)
   *                                  endPtnRadius: {Number} // 起始点波纹大小, 默认15
   *                                  lineStrokeColor: {String} // 线的颜色, 默认 rgba(255, 64, 0, 1)
   *                              }
   *                          ]
   */
  createFlyLine(dataList) {
    this.flyLineFeatures = []
    const effect = new CgsAnimation({
      mapObj: this.map,
    })
    try {
      for (const path of dataList.values()) {
        // 点扩散动画
        const start_c = new CgsCircleAnimation({
          position: path.startPtn,
          radius: path.startPtnRadius || 15,
          fillColor: path.startPtnFillColor || 'rgba(0, 255, 32, 1)',
          duration: 2000,
        })
        const end_c = new CgsCircleAnimation({
          position: path.endPtn,
          radius: path.endPtnRadius || 15,
          fillColor: path.endPtnFillColor || 'rgba(255, 64, 0, 1)',
          duration: 2000,
        })
        //添加到全局维护变量中
        this.map.addFeature(start_c)
        this.map.addFeature(end_c)
        this.flyLineFeatures.push(start_c)
        this.flyLineFeatures.push(end_c)

        const opt = {
          positions: [path.startPtn, path.endPtn],
          fact: 0.3,
          width: 20,
          fillColor: 'rgba(255,255,0,0.8)',
        }
        const parabola = new CgsParabola(opt)
        this.map.addFeature(parabola)
        this.flyLineFeatures.push(parabola)

        const options = {
          positions: parabola.feature3D.positions,
          width: 6,
          time: 5000,
          evenColor: 'rgba(255,255,255,1)',
        }
        const flyLine = new CgsFlyLine(options)
        this.flyLineFeatures.push(flyLine)
        this.map.addFeature(flyLine)

        const curveopt = {
          effectObj: effect,
          startlonlat: path.startPtn,
          endlonlat: path.endPtn,
          bdirection: true,
          id: 'curve' + path.name,
          fillColor: 'rgba(0,255,0,1)',
          width: 4,
          length: 10,
          time: 3000,
          opacity: 1.0,
          type: 'curve',
          clickcall: function (e, that) {
            console.info(e)
            console.info(that)
            console.info(this)
          },
        }
        const curve = new CgsCurve(curveopt)

        const fcurveopt = {
          effectObj: effect,
          startlonlat: path.startPtn,
          endlonlat: path.endPtn,
          bdirection: true,
          id: 'flycurve' + path.name,
          fillColor: 'white',
          width: 4,
          length: 10,
          time: 3000,
          opacity: 1.0,
          type: 'flycurve',
        }
        const flycurve = new CgsCurve(fcurveopt)
        this.map.addFeature(curve)
        this.map.addFeature(flycurve)
        this.flyLineFeatures.push(curve)
        this.flyLineFeatures.push(flycurve)
      }
    } catch (e) {
      console.log('飞线数据初始化失败', e)
    }
  }

  /**
   * 清除飞线动画数据
   */
  clearFlyLine() {
    //删除feature要素
    for (let i = 0; i < this.flyLineFeatures.length; ++i) {
      window.map.removeFeature(this.flyLineFeatures[i])
    }
    this.flyLineFeatures = []
  }

  /**
   * 地图燃烧效果
   * @param {Object} config
   *                  {
   *                      position: [], // 燃烧点
   *                      radius: Number, // 燃烧半径 m
   *                  }
   * @returns
   */
  createFireParticle(config) {
    const optExplode = {
      position: config.position,
      particles: [
        {
          url: 'assets/image/particle/fire.png',
          endColor: 'rgba(0.0,0.0,0.0,0.1)',
          startColor: 'rgba(0.0,0.0,0.0,1.0)',
          startScale: 2.5,
          endScale: 3.0,
          minSpeed: 2.5,
          maxSpeed: 5.0,
          radius: config.radius ? config.radius : 2.0,
          rate: 150,
          rotation: [0.0, 100.0, 0.0],
          width: 20.0,
          height: 20.0,
        },
        {
          url: 'assets/image/particle/fire.png',
          endColor: 'rgba(255.0,0.0,0.0,0.5)',
          startColor: 'rgba(255.0,0.0,0.0,1.0)',
          startScale: 3.5,
          endScale: 2.0,
          minSpeed: 0.5,
          maxSpeed: 1.5,
          radius: config.radius ? config.radius / 2 : 1.0,
          translation: [0.0, 0.0, 1.0],
          rate: 10,
          rotation: [0.0, 100.0, 0.0],
          width: 20.0,
          height: 20.0,
        },
      ],
    }

    try {
      return new CgsExplode(optExplode)
      // explodeFeature;
    } catch (e) {}
  }

  /**
   * @description 添加地图overlay数据面板
   * @param {Array} position 标牌位置信息 必填
   * @param {String} id 维护的标牌id 必填
   * @param {Object}  初始化vue实例的参数对象，用于挂载到overlay上
   * @param {Object} options 其他参数设置
   */
  createMapOverlay(position, id, vueOption = {}, options = {}) {
    if (!Array.isArray(position)) {
      return
    }

    if (!id) {
      return
    }
    if (this.mapOverlay.has(id)) {
      this.mapOverlay.get(id).setVisible(true)
      return
    }

    const infoWrap = document.createElement('div')
    infoWrap.classList.add('map-overlay-panel')
    infoWrap.setAttribute('id', id)
    const mapOverlay = new CgsOverlay({
      position: position,
      positioning: options.positioning || 'bottom-left',
      element: infoWrap,
      offset: options.offset || [20, -20],
      draggable: options.isDrag || false,
      showLine: options.showLine || true,
    })
    this.map.addOverlay(mapOverlay)
    //vue挂载到element上
    // Vue.use(Chdialog)
    // vueOption.el = `#${id}`;
    // new Vue(vueOption);
    // 此处加载已经写好的组件文件，将数据传入进去
    //const InfoVue = Vue.extend(vueOption);
    //new InfoVue().$mount(`#${id}`);
    this.mapOverlay.set(id, mapOverlay)
  }

  /**
   * @description 添加地图气泡
   * @param
   */
  addPopup(position, content, id) {
    if (!Array.isArray(position)) {
      return
    }

    if (!id) {
      return
    }
    if (this.mapOverlay.has(id)) {
      this.removeMapOverlay(id)
    }

    const popup = new CgsPopup({
      position: position,
      content: content,
    })
    this.mapOverlay.set(id, popup)
    this.map.addOverlay(popup)
  }

  /**
   * @description 移除本类中维护的overlay
   * @param {String} id 标牌的id
   */
  removeMapOverlay(id) {
    if (this.mapOverlay.has(id)) {
      this.map.removeOverlay(this.mapOverlay.get(id))
      this.mapOverlay.delete(id)
    }
  }

  /**
   * @description 隐藏overlay
   * @param {String} id 标牌的id
   */
  hiddenMapOverlay(id) {
    if (this.mapOverlay.has(id)) {
      this.mapOverlay.get(id).setVisible(false)
    }
  }

  /**
   * @description 移除地图上所有overlay
   */
  removeAllMapOverlay() {
    for (const overlay of this.mapOverlay.values()) {
      this.map.removeOverlay(overlay)
    }
    this.mapOverlay.clear()
  }

  /**
   *
   * @param {*} serviceUrl
   * @param {*} datasources
   * @param {*} dataset
   * @param {*} sql
   * @param {*} callBack
   */

  /**
   * 基于超图的poi点位分析数据
   * @param serviceUrl {String} 点位分析服务地址
   * @param datasources {String} 数据源名称
   * @param dataset {String} 数据集名称
   * @param sql {String} 查询条件
   * @param callBack {function} 回调函数
   */
  getFeatureBySQL(serviceUrl, datasources, dataset, sql, callBack) {
    // 回调函数问题
    if (typeof callBack !== 'function') {
      callBack(resMsg(false, null, '回调函数错误'))
    }

    // 服务地址传入
    if (!serviceUrl) {
      callBack(resMsg(false, null, '点位分析服务地址解析错误'))
    }

    // 是否传入数据源
    if (!datasources) {
      callBack(resMsg(false, null, '无数据源可查询'))
    }

    // 查询参数
    const sqlParam = new SuperMap.GetFeaturesBySQLParameters({
      queryParameter: {
        name: `${dataset}@${datasources}`,
        attributeFilter: sql,
        // toIndex: 100 // 设置最大返回100条数据
      },
      datasetNames: [`${datasources}:${dataset}`],
    })

    new ol.supermap.FeatureService(serviceUrl).getFeaturesBySQL(sqlParam, function (serviceResult) {
      if (serviceResult.result) {
        if (serviceResult.result.features.features.length === 0) {
          callBack(resMsg(false, null, '未搜索到匹配项'))
        } else {
          callBack(
            resMsg(
              true,
              new ol.format.GeoJSON().readFeatures(serviceResult.result.features),
              '搜索成功'
            )
          )
        }
      } else {
        callBack(resMsg(false, null, '未搜索到匹配项'))
      }
    })
  }

  /**
   * 基于openlayers geoserverWFS空间分析和属性查询 - 获取行政区划分数据
   * @param {Array} rfdwnms 需查询的人防单位内码值
   * @param {String} type 查询返回值类型, coordinates || features 默认 features
   * @param {Object} options 配置项
   *                          {
   *                              url: String 查询服务地址
   *                              featuresNS: String 命名空间URI
   *                              featurePrefix: String 工作区名称
   *                              featureTypes: Array 查询图层
   *                          }
   * @param {Function} callBack 回调函数
   */
  getFeaturesByRfFilter(rfdwnms, type, options, callBack) {
    // 回调函数问题
    if (typeof callBack !== 'function') {
      callBack(resMsg(false, null, '回调函数错误'))
      return
    }

    if (!rfdwnms && rfdwnms.length === 0) {
      return
    }

    const filterConditions = []
    for (const rfdwnm of rfdwnms.values()) {
      filterConditions.push(ol.format.filter.equalTo('rfdwnm', rfdwnm))
    }

    const featureRequest = new ol.format.WFS().writeGetFeature({
      srsName: 'EPSG:4326',
      featureNS: options.featureNS, //命名空间URI
      featurePrefix: options.featurePrefix, //工作区名称
      featureTypes: options.featureTypes, // 查询图层
      outputFormat: 'application/json',
      filter:
        filterConditions.length > 1
          ? ol.format.filter.or(...filterConditions)
          : filterConditions[0],
    })
    fetch(options.url, {
      method: 'POST',
      body: new XMLSerializer().serializeToString(featureRequest),
    })
      .then(function (response) {
        return response.json()
      })
      .then(function (json) {
        if (type === 'coordinates') {
          const features = []
          // 解析出符合cesium的数据格式
          // 因为获得的数据结构层级为四级
          for (let i = 0; i < json.features.length; i++) {
            const coordinates = json.features[i].geometry.coordinates
            const polygonCollection = []
            for (let m = 0; m < coordinates.length; m++) {
              for (let n = 0; n < coordinates[m].length; n++) {
                polygonCollection.push(coordinates[m][n])
              }
            }
            features.push({
              properties: json.features[i].properties,
              polygonCollection: polygonCollection,
            })
          }
          callBack(resMsg(true, features, '查询成功'))
        } else {
          callBack(resMsg(true, new ol.format.GeoJSON().readFeatures(json), '查询成功'))
        }
      })
  }

  /**
   * 基于openlayers geoServer 路径分析查询 - 获取路径数据feature
   * @param {Array} start 起始点
   * @param {Array} end 终点
   * @param {String} type 查询返回值类型, coordinates || features 默认 features
   * @param {Object} options 配置项
   * @param {Function} callBack 回调函数
   */
  getLineByWFSSearch(start, end, type, options, callBack) {
    // // 回调函数问题
    // if (typeof callBack !== 'function') {
    //   callBack(resMsg(false, null, '回调函数错误'))
    //   return
    // }
    // if (!Array.isArray(start) && start.length !== 2) {
    //   callBack(resMsg(false, null, '起始点经纬度错误'))
    //   return
    // }
    // if (!Array.isArray(end) && end.length !== 2) {
    //   callBack(resMsg(false, null, '终点经纬度错误'))
    //   return
    // }
    // let featureRequest = {
    //   srsName: 'EPSG:4326',
    //   service: 'WFS',
    //   version: '1.0.0',
    //   request: 'GetFeature',
    //   typeName: options.typeName,
    //   outputFormat: 'application/json',
    //   viewParams: `x1:${start[0]};y1:${start[1]};x2:${end[0]};y2:${end[1]}`,
    // }
    // fetch(`${options.url}?${qs.stringify(featureRequest)}`, {
    //   method: 'GET',
    // })
    //   .then((response) => {
    //     return response.json()
    //   })
    //   .then((json) => {
    //     if (type === 'coordinates') {
    //       // 解析出数据
    //       if (json.features[0].geometry.type === 'MultiLineString') {
    //         callBack(resMsg(true, json.features[0].geometry.coordinates, '查询成功'))
    //       } else if (json.features[0].geometry.type === 'LineString') {
    //         callBack(resMsg(true, [json.features[0].geometry.coordinates], '查询成功'))
    //       } else {
    //         callBack(resMsg(false, [], '查询失败，未知格式'))
    //       }
    //     } else {
    //       callBack(resMsg(true, new ol.format.GeoJSON().readFeatures(json), '查询成功'))
    //     }
    //   })
  }

  /**
   * 基于openlayers geoServer 查询栅格影像值
   * @param {String} type 查询返回值类型, coordinates || features 默认 features
   * @param {Object} options 配置项
   * @param {Function} callBack 回调函数
   */
  getGridImageValueByWFS(url, queryLayer, position, callBack) {
    // 回调函数问题
    if (typeof callBack !== 'function') {
      callBack(resMsg(false, null, '回调函数错误'))
      return
    }

    if (!Array.isArray(position) || position.length !== 2) {
      callBack(resMsg(false, null, '输入点错误'))
      return
    }

    const rect = deltaRect(position)

    const searchUrl = `${url}?SERVICE=WMS&VERSION=1.1.0&REQUEST=GetFeatureInfo&FORMAT=image%2Fpng&TRANSPARENT=true&QUERY_LAYERS=${encodeURIComponent(
      queryLayer
    )}&LAYERS=${encodeURIComponent(
      queryLayer
    )}&STYLES=&INFO_FORMAT=application%2Fjson&X=50&Y=50&SRS=EPSG%3A4326&WIDTH=101&HEIGHT=101&BBOX=${encodeURIComponent(
      rect.minx + ',' + rect.miny + ',' + rect.maxx + ',' + rect.maxy
    )}`
    fetch(searchUrl, {
      method: 'GET',
    })
      .then((Response) => {
        return Response.json()
      })
      .then((res) => {
        callBack(resMsg(true, res.features[0].properties.GRAY_INDEX, '查询成功'))
      })
      .catch((e) => {
        console.log('查询栅格值失败, ', e)
      })
  }

  /**
   * @description 基于 webworker 结合 turf.js 计算融合数据
   * @param {Object} config
   *                      {
   *                          type: String, 处理的geometry类型, 'circle' || 'polygon',  '默认polygon',
   *                          positions: Array3 形如 [[[],[],...],...], 带融合的数据点, type === 'polygon'
   *                          circles:  形如 [
   *                                     {
   *                                         center: [],
   *                                         radius: Number, 米
   *                                      }
   *                                   ]， type === 'circle'
   *                      }
   * @returns { Object }
   */
  unionPolygonByTurf(config) {
    if (!config.type) {
      return
    }

    return new Promise((resolve) => {
      const featureList = config.type === 'circle' ? config.circles : config.positions
      const workProcessDataNum = 200 // 单个线程计算数量
      let workerNum = 0 // 分发线程数
      let compeleteWorkerNum = 0 // 完成线程数
      const unionList = [] // 每个线程返回的计算值
      const thisNum = Math.ceil(featureList.length / workProcessDataNum) // 每200个分发到一个线程

      // 线程分发
      for (let c = 0; c < thisNum; c++) {
        const workerConfig = {
          type: config.type,
        }
        if (c === this.Number) {
          workerConfig[config.type === 'circle' ? 'circles' : 'positions'] = featureList.slice(
            (c - 1) * workProcessDataNum,
            featureList.length
          )
        } else {
          workerConfig[config.type === 'circle' ? 'circles' : 'positions'] = featureList.slice(
            c * workProcessDataNum,
            (c + 1) * workProcessDataNum
          )
        }
        // 开辟线程
        const liteWorker = new Worker('./jslib/union/unionControl.js', {
          name: 'jbqfwWorker' + (workerNum + 1),
        })
        liteWorker.postMessage(workerConfig)
        workerNum++
        liteWorker.onmessage = function (e) {
          unionList.push(e.data)
          compeleteWorkerNum++
        }
      }

      // 监测线程完成情况
      let animation = null
      ;(function watchWorkerProcess() {
        if (workerNum === compeleteWorkerNum) {
          // 线程完成
          cancelAnimationFrame(animation)
          const union = turf.union(...unionList)
          resolve({
            // 解析出两种数据格式, Polygon 和 multiPolygon
            coordinates:
              union.geometry.type === 'Polygon'
                ? [union.geometry.coordinates]
                : union.geometry.coordinates,
            GeoJSON: union,
          })
        } else {
          animation = requestAnimationFrame(watchWorkerProcess)
        }
      })()
    })
  }

  /**
   * @description 基于 turf.js 计算polygon差值数据
   * @param {Object} config
   *                      {
   *                          subPolygonCoordiantes: [][][][], 裁剪多边形coordinates数据
   *                          polygonCoordinates: [][][], 待裁剪多边形的coordinates数据
   *                      }
   */
  differencePolygonByTurf(config) {
    if (!Array.isArray(config.subPolygonCoordiantes)) {
      return
    }
    if (!Array.isArray(config.polygonCoordinates)) {
      return
    }
    try {
      const polygon = turf.multiPolygon(config.polygonCoordinates)
      const subPolygon = turf.multiPolygon(config.subPolygonCoordiantes)

      const diffPolygon = turf.difference(polygon, subPolygon)

      if (!diffPolygon) {
        return
      }

      return {
        coordinates:
          diffPolygon.geometry.type === 'Polygon'
            ? [diffPolygon.geometry.coordinates]
            : diffPolygon.geometry.coordinates,
        GeoJSON: diffPolygon,
      }
    } catch (e) {
      console.log('计算差值失败, ', e)
    }
  }

  /**
   * @description 基于 turf.js 计算 feature 面积
   * @param {Object} GeoJSON json数据
   */
  calcArea(GeoJSON) {
    return turf.area(GeoJSON)
  }

  /**
     *
     * @description 向地图添加图片feature数据
     * @param {Object} options 配置项 {
     *      position : this.$config.mapConfig.mapCenters,
            name :"label",
            labelfont: "24px 微软雅黑 ",
            labelfill : "rgba(255,0,0,1.0)",
            labeloffset : [0,20]
     * }
     */
  createTxtLable(options) {
    const label = new CgsLabel(options)
    this.map.addFeature(label)
    return label
  }

  /**
   * @description 添加地图绘制编辑事件
   */
  createDTool() {
    const dTool = new CgsDrawByMouse({
      map: this.map,
      mode: CgsDrawByMouse.RectangleMode,
      createOptions: {
        fillColor: 'yellow',
        width: 4,
      },
      onCancel: function () {
        console.log('取消时')
      },
      onDrawEnd: function (f) {
        console.log('绘制的要素为', f)
      },
    })
    dTool.activate()
    // dTool.deactivate();
  }

  /**
   * 漫游方法
   * @param {Object}} manipulatePoints
   */
  //漫游的方法
  startManipulate(manipulatePoints) {
    const _this = this
    const cameraInfo = manipulatePoints[0]
    cameraInfo.complete = function () {
      if (manipulatePoints.length != 1) {
        _this.v =
          CgsGeometry.measure2PointDistance(
            manipulatePoints[0].destination,
            manipulatePoints[1].destination
          ) / manipulatePoints[1].duration //走向下一个点的速度
        manipulatePoints.splice(0, 1) //删除第一个元素
        _this.startManipulate(manipulatePoints)
      }
    }
    _this.map.setPointManipulate(cameraInfo)
  }

  //解析数组，调用漫游的方法
  mapRoam(cameraPositions) {
    this.stopPoint = null
    this.roamStop = false

    this.manipulatePoints = cameraPositions
    this.startManipulate(this.manipulatePoints)
  }

  //暂停漫游----点击之后会形成新的json
  mapCanceFlight() {
    if (this.manipulatePoints.length === 0) {
      return
    }
    this.roamStop = true
    this.map.map3D.camera.cancelFlight()
    //获取当前的相机信息
    const cameraInfo = this.map.getCameraInfo()
    this.stopPoint = cameraInfo
    if (this.v != 0) {
      const distance = CgsGeometry.measure2PointDistance(
        this.manipulatePoints[0].destination,
        this.objToArr(cameraInfo.position)
      ) //算当前点与下一个点的距离
      const time = distance / this.v //飞到下一个点的时间
      this.manipulatePoints[0].duration = time
    } else {
      this.manipulatePoints[0].duration = this.manipulatePoints[0].duration * 0.75
    }
  }

  //继续漫游
  mapContinueFlight() {
    if (!this.manipulatePoints || !this.roamStop) {
      return
    }
    this.map.setCameraInfo({
      duration: 0.5,
      position: this.stopPoint.position,
      rotation: this.stopPoint.rotation,
    })

    const _this = this
    setTimeout(function () {
      _this.startManipulate(_this.manipulatePoints)
      _this.roamStop = false
    }, 500)
    // this.startManipulate(this.manipulatePoints);
    // this.roamStop = false
  }

  /**
   *
   * @param {Array} bounds 生成点所属的地图边界, wgs48格式 {west: 118.7872266769, south: 32.1794700623, east: 118.8328027725, north: 32.2095966339}
   * @param {Number} number  生成数量
   */
  generteRandomPosition(bounds, number) {
    if (!bounds) {
      return []
    }

    if (number <= 0) {
      return []
    }

    const points = []
    for (let i = 0; i < number; i++) {
      points.push([
        bounds.west + Math.random() * (bounds.east - bounds.west),
        bounds.south + Math.random() * (bounds.north - bounds.south),
      ])
    }

    return points
  }

  /**
   * @description 地图事件绑定
   */
  bindEvent() {
    const featureTypes = ['CgsMark', 'CgsRect', 'CgsLine', 'CgsCircle', 'CgsPolygon', 'CgsPoint']
    // feature点击事件
    const featureClick = window.CgsSubPub.subscribe(
      CgsEvent.eFeatureClick,
      function (e, feature, position, features) {
        if (featureTypes.indexOf(feature.getType()) != -1) {
          const config = feature.getProperties()
          if (config.click && typeof config.click === 'function') {
            config.click(e, feature, position, features, config)
          }
        }
      }
    )
    this.eventList.push({
      name: 'featureClick',
      e: featureClick,
    })

    // 地图缩放事件
    // let mapZoomChanged = window.CgsSubPub.subscribe(CgsEvent.eZoomChanged, function (e, map) {
    // });
    // this.eventList.push({
    //     name: 'mapZoomChanged',
    //     e: mapZoomChanged
    // });
  }

  bindMouseHoverEvent() {
    // 地图鼠标移入事件
    const mapMouseEnter = window.CgsSubPub.subscribe(
      CgsEvent.eFeatureHover,
      function (e, feature, position, features) {
        if (
          feature.getType() === 'CgsPolygon' &&
          feature.getProperties().info &&
          feature.getProperties().info.User_level
        ) {
          const featuresGroup = window.map.getFeatureGroupByName(feature.groupName).getAllFeatures()
          for (const polygon of featuresGroup.values()) {
            polygon.setFillColor('rgba(0,255,255,0.3)')
          }
        }
      }
    )
    this.eventList.push({
      name: 'mapMouseEnter',
      e: mapMouseEnter,
    })

    // 地图鼠标移出事件
    const mapMouseLeave = window.CgsSubPub.subscribe(
      CgsEvent.eFeatureLeave,
      function (e, feature, position, features) {
        if (
          feature.getType() === 'CgsPolygon' &&
          feature.getProperties().info &&
          feature.getProperties().info.User_level
        ) {
          const featuresGroup = window.map.getFeatureGroupByName(feature.groupName).getAllFeatures()
          for (const polygon of featuresGroup.values()) {
            polygon.setFillColor('rgba(0,255,255,0.1)')
          }
        }
      }
    )
    this.eventList.push({
      name: 'mapMouseLeave',
      e: mapMouseLeave,
    })
  }

  unBindMouseHoverEvent() {
    for (const event of this.eventList.values()) {
      if (event.name === 'mapMouseEnter' || event.name === 'mapMouseLeave') {
        CgsSubPub.unsubscribe(event.e)
      }
    }
  }

  /**
   * @description 地图事件解绑, 工具类维护的事件全部解绑
   */
  unBindEvent() {
    for (const event of this.eventList.values()) {
      CgsSubPub.unsubscribe(event.e)
    }
  }

  /**
   * @description 点位显隐控制
   */
  setLayerVisible(name, flag) {
    const points = this[name]
    if (!points) {
      return
    }
    points.forEach((point) => {
      point.setVisible(flag)
    })
  }

  // 关闭地图弹窗
  closeInfoWindow() {
    if (this.infoWindowObj.length) {
      if (this.infoWindowObj.length) {
        this.infoWindowObj.forEach((infoWindow) => {
          this.map.removeOverlay(infoWindow)
        })
        this.infoWindowObj = []
      }
    }
  }
}

/**
 * 回调函数
 */
const resMsg = function (result, data, msg) {
  const obj = new Object()
  obj.result = result
  obj.data = data
  obj.msg = msg
  return obj
}

/**
 * 根据中心点计算δ矩形
 */
function deltaRect(point, delta) {
  const offset = delta || 0.00001
  const minx = point[0] - offset
  const miny = point[1] - offset
  const maxx = point[0] + offset
  const maxy = point[1] + offset

  return {
    minx: minx,
    miny: miny,
    maxx: maxx,
    maxy: maxy,
  }
}

export default Map3DControl
